/**
 * Copyright (C)  Gadglet .
 *
 * This file is part of Gadglet
 *
 * Gadglet is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Gadglet is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Gadglet. If not, see <http://www.gnu.org/licenses/>.
 */

package com.gadglet.data;

import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import com.gadglet.core.RequestException;
import com.gadglet.data.utils.DomainAccountStatus;
import com.gadglet.data.utils.DomainUserStatus;
import com.gadglet.data.utils.PMF;
import com.gadglet.params.SharedConstants;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

/**
 * Utility class to handle DomainAccount methods
 *
 */
public class DomainAccountUtils {
	static Logger log = Logger.getLogger("DomainAccountUtils");

	/**
	 * @return the creator of the DomainAccount
	 */
	public static String getMyAccountAdmins() {
		String adminName = null;

		return adminName;
	}

	/**
	 * Load the DomainAccount when accessing the server with OpenId during registration
	 * @param openIDAuthDomain
	 * @return
	 */
	public static DomainAccount getDomainAccountByAuthDomain(
			String openIDAuthDomain) {
		// see security
		DomainAccount account = null;

		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.currentTransaction().begin();
		Query query = pm.newQuery(DomainAccount.class);
		try {

			query.setFilter("openIDAuthDomain == nameParam");
			query.declareParameters("String nameParam");
			query.setUnique(true);
			account = (DomainAccount) query.execute(openIDAuthDomain);
		} catch (Exception e) {
			log.warning(e.getMessage());
		} finally {
			if (pm.currentTransaction().isActive())
				pm.currentTransaction().rollback();

			pm.close();
		}

		return account;
	}

	/**
	 * @param id
	 * @return
	 */
	public static DomainAccount getDomainAccountByID(String id) {
		// see security
		DomainAccount account = null;

		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.currentTransaction().begin();
		Query query = pm.newQuery(DomainAccount.class);
		try {

			query.setFilter("accountId == nameParam");
			query.declareParameters("String nameParam");
			query.setUnique(true);
			account = (DomainAccount) query.execute(id);
		} catch (Exception e) {
			log.warning(e.getMessage());
		} finally {
			if (pm.currentTransaction().isActive())
				pm.currentTransaction().rollback();

			pm.close();
		}

		return account;
	}

	/**
	 * Create a new DomainAccount and its first user
	 * @param token
	 * @param timeZone
	 * @param registrationMethod
	 * @return
	 * @throws RequestException
	 */
	public static DomainAccount createNewDomainAndAdminUser(
			RegistrationToken token, String timeZone, String registrationMethod, int maxActiveUsers) throws RequestException {

		UserService userService = UserServiceFactory.getUserService();
		User user = userService.getCurrentUser();

		DomainAccount newAccount = null;
		DomainUser firstUser = null;
		DomainAccount existingdAccount = null;
		String accountId = null;

		PersistenceManager pmToken = PMF.get().getPersistenceManager();
		PersistenceManager pmDomain = PMF.get().getPersistenceManager();
		PersistenceManager pmUser = PMF.get().getPersistenceManager();

		if (registrationMethod
				.equalsIgnoreCase(SharedConstants.registrationMethodDual)
				&& token.getOauthUserId() != null
				&& !token.getOauthUserId().equalsIgnoreCase(user.getUserId())) {
			log.warning("security warning, token with oauthId ="
					+ token.getOauthUserId() + "\nwas claimed with openid="
					+ user.getUserId());
			// delete the token

			pmToken.currentTransaction().begin();
			Query regQry = pmToken.newQuery(RegistrationToken.class);
			regQry.setUnique(true);
			regQry.setFilter("tokenId == code");
			regQry.declareParameters("String code");
			token = (RegistrationToken) regQry.execute(token.getTokenID());

			try {
				pmToken.deletePersistent(token);
				pmToken.currentTransaction().commit();

			} catch (Exception e) {
				printStackTrace(e);
			} finally {
				if (pmToken.currentTransaction().isActive())
					pmToken.currentTransaction().rollback();
				pmToken.close();
			}
			throw new RequestException("userChangedIdOnRegistration");
		}

		Query accountQry = pmDomain.newQuery(DomainAccount.class);
		try {

			accountQry.setFilter("openIDAuthDomain == nameParam");
			accountQry.declareParameters("String nameParam");
			accountQry.setUnique(true);
			existingdAccount = (DomainAccount) accountQry.execute(user
					.getAuthDomain());
			accountQry.closeAll();

			if (existingdAccount == null) {
				newAccount = new DomainAccount(maxActiveUsers);
				pmDomain.currentTransaction().begin();
				pmDomain.makePersistent(newAccount);
				pmDomain.currentTransaction().commit();
				accountId = newAccount.getAccountId();
			} else
				accountId = existingdAccount.getAccountId();

		} catch (Exception e) {
			printStackTrace(e);
		} finally {

			if (pmDomain.currentTransaction().isActive())
				pmDomain.currentTransaction().rollback();

			pmDomain.close();

		}

		try {
			firstUser = new DomainUser(user.getUserId(), accountId,
					user.getEmail(), user.getNickname(),
					DomainUserStatus.ACTIVE.getUserStatus(), timeZone, true,
					user.getAuthDomain(), token.getAuthDomain(),
					token.getOpenSocialViewerId(), token.getConsumerKey());

			pmUser.currentTransaction().begin();
			pmUser.makePersistent(firstUser);
			pmUser.currentTransaction().commit();

		} catch (Exception e) {
			printStackTrace(e);
		} finally {

			if (pmUser.currentTransaction().isActive())
				pmUser.currentTransaction().rollback();

			pmUser.close();

		}

		try {
			pmToken.currentTransaction().begin();
			Query regQry = pmToken.newQuery(RegistrationToken.class);
			regQry.setUnique(true);
			regQry.setFilter("tokenId == code");
			regQry.declareParameters("String code");
			token = (RegistrationToken) regQry.execute(token.getTokenID());
			if (token != null)
				pmToken.deletePersistent(token);
			pmToken.currentTransaction().commit();

		} catch (Exception e) {
			printStackTrace(e);
		} finally {
			if (pmToken.currentTransaction().isActive())
				pmToken.currentTransaction().rollback();
			pmToken.close();
		}

		return newAccount;
	}

	public static void changeStatus(String id, DomainAccountStatus status) {

		// security

		DomainAccount account = getDomainAccountByID(id);
		account.setStatus(status.getAccountStatus());
		try {
			account.save();
		} catch (Exception e) {
			log.warning(e.getMessage());
		}
	}

	static protected void printStackTrace(Exception e) {
		StackTraceElement[] stackTrace = e.getStackTrace();
		if (stackTrace != null) {
			final String newLine = System.getProperty("line.separator");
			// final String headerLine =
			// "-----------------------------------------------------------------------";
			final String headerTitlePortion = "-- StackTraceElement Index #";
			int index = 0;
			StringBuffer msg = new StringBuffer();
			msg.append(e.getMessage() + newLine);
			for (StackTraceElement element : stackTrace) {
				final String exceptionMsg = "Exception thrown from "
						+ element.getMethodName() + " in class "
						+ element.getClassName() + " [on line number "
						+ element.getLineNumber() + " of file "
						+ element.getFileName() + "]";

				msg.append((headerTitlePortion + index++ + newLine));
				msg.append((exceptionMsg + newLine + newLine).getBytes()
						.toString());
				msg.append(("Exception.toString: " + element.toString() + newLine));

			}
			log.warning(msg.toString());
		} else
			log.warning(e.getMessage());
	}
}
